
/**
 * 给红包分配等级 10级 未来3分钟内，根据当前红包池数量定等级
 * 给设备分配等级 10级 1/10 如：为1级 
 */
import { AutoUser, KsLiveRoom, KsRedPacket } from '@sker/entities';
import dayjs from 'dayjs';
import { RedisClientType } from 'redis';

export class CoreRed {
    minTime: number;
    maxTime: number;

    count: number;
    id: number;
    link: string;
    open_time: Date;
    room_id: number;
    user_id: string;
    name: string;
    online: number;
    join: number;
    type: string;
    origin: any;
    get money_V(): number {
        if (this.type === '口令' || this.type === '快币' || this.type === '穿云箭') {
            return parseInt(`${100 * this.count * Math.sqrt(this.count) / this.online}`) / 100;
        }
        if (this.type === '粉丝团') {
            return parseInt(`${100 * this.count / this.online}`) / 100;
        }
        return 0;
    }
    canUse(): boolean {
        const openTime = dayjs(this.open_time).toDate().getTime()
        if (this.type === '口令' || this.type === '快币') {
            const endDate = dayjs().add(this.maxTime, 'second').toDate().getTime()
            if (openTime > endDate) {
                return false
            };
            const startDate = dayjs().add(this.minTime, 'second').toDate().getTime()
            if (openTime < startDate) {
                return false
            };
        }
        if (this.type === '穿云箭' || this.type === '粉丝团') {
            const endDate = dayjs().add(this.maxTime, 'second').toDate().getTime()
            if (openTime > endDate) {
                return false
            };
            const startDate = dayjs().add(8, 'second').toDate().getTime()
            if (openTime < startDate) {
                return false
            };
            return true;
        }
        return true;
    }
}
export class CoreDevice {
    owner: string;
    uuid: string;
    score: number;
    setting: any;
}


const getMin = (a: number, b: number) => a > b ? b : a;
const getMax = (a: number, b: number) => a > b ? a : b;

export class Core {
    constructor(private r: RedisClientType, private user?: AutoUser) { }
    async getDeviceRed(types: string[], mobile: string, uuid: string, setting?: any) {
        const allCoreReds = await this.getCoreReds(types, mobile);
        const allLocks = await this.getAllDeviceLocks(uuid)
        // 去掉已经分配过的房间
        const coreReds = allCoreReds.filter(it => {
            if (allLocks.roomIds.includes(it.room_id)) return false;
            return true;
        });
        // 红包等级
        const level = coreReds.length;
        if (level === 0) return [];
        if (uuid === 'xxx') {
            return coreReds;
        }
        // 获取未开空闲设备等级
        const totalDevices = await this.getDevices(mobile);
        if (totalDevices.length === 0) {
            return coreReds;
        }
        // 拿到所有红包
        let min = setting?.minJoinTime || setting?.minTime || 10;
        let max = setting?.minOpenTime || setting?.maxTime || 10;
        let min2 = 10;
        if (setting.join_type && setting.join_type === 'share') {
            min += 10;
            min2 += 10;
            max += 10;
        }
        const redsList = coreReds.filter(it => {
            if (!types.includes(it.type)) return false;
            if (it.type === '穿云箭') return true;
            // const openTime = dayjs(it.open_time).toDate().getTime()
            // const nowTime = dayjs().toDate().getTime()
            // if (it.type === '口令') {
            //     if ((openTime - nowTime) > (getMax(min, max)) * 1000 + 5 * 1000) return false;
            //     if ((openTime - nowTime) < (getMin(min, max)) * 1000 + 5 * 1000) return false;
            // } else {
            //     if ((openTime - nowTime) > (getMax(min, max)) * 1000) return false;
            //     if ((openTime - nowTime) < (getMin(min, max)) * 1000) return false;
            // }
            return (it.count / it.online) >= 0.6;
        })
        let red: any = undefined;
        const cyj = redsList.filter(it => it.type === '穿云箭').sort((a, b) => {
            if (b.count === a.count) {
                const aOpenTime = dayjs(a.open_time).toDate().getTime()
                const bOpenTime = dayjs(b.open_time).toDate().getTime()
                return aOpenTime - bOpenTime;
            }
            return b.count - a.count
        })
        if (cyj && cyj.length > 0) {
            red = cyj[0]
        } else {
            const reds = redsList.sort((a, b) => {
                return b.count * Math.sqrt(b.count) / b.online - a.count * Math.sqrt(b.count) / a.online
            })
            if (reds && reds.length > 0) {
                red = reds[0]
            }
        }
        // const myLevel2 = Math.random() * totalDevices.length
        // 每个档次的数量
        // let red = coreReds[0];
        // const eventLevelCount = totalDevices.length / level;
        // const index = totalDevices.findIndex(it => it === uuid)
        // let myLevel = Math.floor((index + 1) / eventLevelCount);
        // if (myLevel === 1 && coreReds.length === 1) {
        //     myLevel = 0;
        // }
        // let red = coreReds[myLevel];
        // if (!red && myLevel > 0) {
        //     red = coreReds[myLevel - 1]
        // }
        // const red = coreReds[0]
        // console.log(`${myLevel}/${level}`)
        if (!red) return [];
        // 增加计数
        const lockKey = `lock.${mobile}.${red.room_id}`
        const lock = await this.get<{ count: number, room_id: number, owner: string }>(lockKey)
        const expireTime = Math.floor((dayjs(red.open_time).toDate().getTime() - dayjs().toDate().getTime()) / 1000)
        if (lock) {
            lock.count += 1;
            await this.set(lockKey, lock, expireTime)
        } else {
            await this.set<{ count: number, room_id: number, owner: string }>(lockKey, { count: 1, room_id: red.room_id, owner: mobile }, expireTime)
        }
        // lock device
        const lockDeviceKey = `lock.device.${uuid}.${red.room_id}`;
        await this.set(lockDeviceKey, { room_id: red.room_id, uuid, open_time: dayjs(red.open_time).toDate().getTime() }, expireTime)
        return [red];
    }

    async getAllLocks(mobile: string, max: number) {
        const key = `lock.${mobile}.*`
        const list = await this.all<{ count: number, room_id: number, owner: string }>(key)
        return list.filter(it => !!it).filter(it => it.count >= max).map(it => it.room_id)
    }
    async getAllDeviceLocks(uuid: string) {
        const key = `lock.device.${uuid}.*`;
        const list = await this.all<{ uuid: string, room_id: number, open_time: number }>(key)
        const filterList = list.filter(it => !!it)
        const roomIds = filterList.map(it => it.room_id)
        // const sortTimeList = filterList.sort((a, b) => b.open_time - a.open_time)
        return {
            roomIds,
            maxOpenTime: 0
        }
    }
    async all<T>(key: string): Promise<T[]> {
        const keys = await this.r.keys(key)
        if (keys && keys.length > 0) {
            const list = await this.r.mGet(keys);
            return list.map(val => this.parseJson(val))
        }
        return []
    }
    private parseJson(val: string) {
        if (!val) return val;
        try {
            return JSON.parse(val)
        } catch (e) {
            return val;
        }
    }
    private async set<T>(key: string, value: T, expire: number) {
        await this.r.set(key, JSON.stringify(value))
        await this.r.expire(key, expire)
    }
    private async get<T>(key: string): Promise<T> {
        return this.r.get(key).then(r => this.parseJson(r))
    }
    // 更新设备分数
    async updateDeviceScore(device: CoreDevice) {
        await this.r.zAdd(`owner.${device.owner}`, { score: device.score, value: device.uuid })
        const expirationTime = Math.floor((dayjs().endOf('day').toDate().getTime() - new Date().getTime()) / 1000)
        await this.r.expire(`owner.${device.owner}`, expirationTime)
    }
    // 获取所有设备
    async getDevices(owner: string) {
        const devices = await this.r.zRange(`owner.${owner}`, 0, -1)
        return devices;
    }
    // 添加红包
    async addLiveRoomWithReds(room: KsLiveRoom, reds: KsRedPacket[]) {
        const key = `rooms.${room.user_id}`
        await this.r.set(key, JSON.stringify({
            ...room,
            reds,
            join: 0
        }));
        const expireTime = Math.floor((dayjs(room.open_time).toDate().getTime() - dayjs().toDate().getTime()) / 1000)
        await this.r.expire(key, expireTime)
    }
    // hello 
    // 获取红包
    async getCoreReds(types: string[], mobile: string): Promise<CoreRed[]> {
        const maxNumber = this.user?.setting?.maxCount || 7;
        const lockedReds = await this.getAllLocks(mobile, maxNumber)
        const rooms = await this.r.keys('rooms*')
        if (rooms && rooms.length > 0) {
            const list = await this.r.mGet(rooms);
            const allList = list.map(it => {
                try {
                    return JSON.parse(it)
                } catch (e) {
                    return;
                }
            }).map((it: KsLiveRoom & { reds: KsRedPacket[], join: number }) => {
                if (!it) return [];
                if (!it.reds) return [];
                if (it.reds.length === 0) return [];
                if (lockedReds.includes(it.id)) return [];
                const reds = it.reds.filter(red => types.includes(red.type));
                if (reds.length === 0) {
                    return [];
                };
                return reds.map(red => {
                    it.join = it.join || 0;
                    const coreRed = new CoreRed();
                    coreRed.minTime = this.user?.setting?.minTime || 60;
                    coreRed.maxTime = this.user?.setting?.maxTime || 60 * 1.5;
                    coreRed.count = red.count;
                    coreRed.id = red.id;
                    coreRed.link = it.link;
                    coreRed.open_time = it.open_time;
                    coreRed.room_id = it.id;
                    coreRed.user_id = it.user_id;
                    coreRed.name = it.name;
                    coreRed.online = it.online;
                    coreRed.join = it.join || 0;
                    coreRed.type = red.type;
                    coreRed.origin = it;
                    if (coreRed.canUse()) {
                        return coreRed;
                    }
                    return;
                })
            }).flat().filter(it => !!it).sort((a, b) => b.money_V - a.money_V)
            return allList;
        }
        return []
    }
}